﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Afficheur
{
    /// <summary>
    /// Assemblage de 7 segments pour en faire un afficheur 7 segments
    /// </summary>
    public partial class unDigit : UserControl
    {
        /// <summary>
        /// La plus petite valeur que peut afficher l'afficheur
        /// </summary>
        private const short MINVALUE = 0;

        /// <summary>
        /// La plus grande valeur que peut afficher l'afficheur. Par construction,
        /// l'afficheur ne peut afficher que 16 valeur différentes, mais il est 
        /// possible de limiter la plage de valeurs à un nombre plus réduit.
        /// </summary>
        private short maxValeur;

        /// <summary>
        /// Les caractéristiques de l'afficheur 7 segments
        /// couleur, valeur, allumage/extinction
        /// </summary>
        private SegmentColor couleur;
        private short valeur;
        private Boolean on;

        /// <summary>
        /// Données de gestion pour le redimensionnment de l'afficheur
        /// </summary>
        private int initialWidth;
        private int initialHeight;

        /// <summary>
        /// Constructeur de l'afficheur
        /// </summary>
        public unDigit()
        {
            InitializeComponent();

            this._MaxValeur = 9;

            this._Couleur = SegmentColor.blue;
            this._Valeur = 0;
            this._On = true;

            this.initialWidth = this.Width;
            this.initialHeight = this.Height;
        }

        /// <summary>
        /// Propriété permettant de gérer la couleur d'affichage du segment
        /// </summary>
        public SegmentColor _Couleur
        {
            get { return couleur; }
            set
            {
                // on mémorise la couleur
                this.couleur = value;
                // Mise à jour de la couleur sur chaque segment
                foreach (Control ctrl in this.Controls)
                {
                    ((Segment)ctrl)._Color = value;
                }
            }
        }

        /// <summary>
        /// Propiété permettant de gérer l'allumage/extinction de l'afficheur
        /// </summary>
        public Boolean _On
        {
            get { return this.on; }
            set 
            {
                this.on = value;
                if (this.on)
                {
                    this._Valeur = this.valeur;
                }
                else
                {
                    foreach (Control ctrl in this.Controls)
                    {
                        ((Segment)ctrl)._On = this.on;
                    }
                }

            }
        }

        /// <summary>
        /// Propriété permettant de gérer la valeur affichée par l'afficheur
        /// </summary>
        public short _Valeur
        { 
            get {return valeur;}
            set
            {
                Boolean i1, i2, i3, i4;

                if (value >= MINVALUE && value <= this.maxValeur)
                {
                    this.valeur = value;
                    if (this.on)
                    {
                        // i1 à i4 représentent les 4 entrées de commande de l'afficheur
                        // i1 à i4 sont les représentations booléennes des 4 bits équivalents 
                        // à la valeur à afficher
                        i1 = ((value & 8) == 8);
                        i2 = ((value & 4) == 4);
                        i3 = ((value & 2) == 2);
                        i4 = ((value & 1) == 1);

                        this.segmentA._On = (!(i1) && i3) || (i1 && !(i4)) || (i2 && i3) || !(i2 || i4) || (i1 && !(i2) && !(i3)) || (!(i1) && i2 && i4);
                        this.segmentB._On = !(i1 || i2) || !(i2 || i3) || !(i2 || i4) || (!(i1) && !(i3 ^ i4)) || (i1 && !(i3) && i4);
                        this.segmentC._On = (i1 ^ i2) || (!(i3) && i4) || (!(i3 ^ i4) && !(i2));
                        this.segmentD._On = (i1 && !(i3)) || !(i1 || i2 || i4) || (i2 && (i3 ^ i4)) || (!(i2) && i3 && i4);
                        this.segmentE._On = !(i2 || i4) || (i3 && !(i4)) || (i1 && i2) || (i1 && i3);
                        this.segmentF._On = (i1 && !(i2)) || !(i3 || i4) || (!(i3) && (i1 ^ i2)) || (i1 && i3) || (i2 && !(i4));
                        this.segmentG._On = (i3 && (i1 || !(i2) || !(i4))) || (i1 && i4) || (!(i3) && (i1 ^ i2));
                    }
         
                }
                else
                {
                    throw new ArgumentOutOfRangeException("value","La valeur attendue doit être comprise entre " + MINVALUE + " et " + maxValeur  + " inclus");
                }
            }
        }

        /// <summary>
        /// Propriété permettant de d'empêcher que la valeur max à afficher 
        /// dépasse 15, car par construction, cet afficheur ne peut afficher 
        /// que 16 valeurs différentes (16 valeurs de commande i1 à i4)
        /// </summary>
        public short _MaxValeur
        {
            get { return maxValeur; }
            set 
            { 
                if (value <= 15)
	            {
		            maxValeur = value;
            	}
                else
                {
                    maxValeur = 15;
                }
            }
        }
 
        /// <summary>
        /// Une première version de redimensionnement de l'afficheur
        /// Cette fonction produit une dérive très rapidement perceptible
        /// qui s'accroit au fur et à mesure des redimensionnements successifs
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void unDigit_Resize(object sender, EventArgs e)
        {
            SizeF factor = new SizeF((float)this.Width / initialWidth, (float)this.Height / initialHeight);
            foreach (Control c in this.Controls)
            {
                c.Scale(factor);
            }
            this.initialWidth = this.Width;
            this.initialHeight = this.Height;
        }
    }
}
